package org.aerie.forest.core.frame.rebar.factory;

import java.lang.reflect.Modifier;

import org.aerie.forest.core.frame.init.ForestFrameContext;

import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod;

/**
 * @description 入库组件生成器
 *
 * @author quark
 * @organization aerie
 * @date 2020年2月27日 下午1:03:17
 * @version 1.2.0
 */
enum StorageBuilder implements ForestFactoryComponent {

	/**
	 * @description 单例
	 * 
	 * @author quark
	 * @date 2020年2月27日 下午4:55:19
	 * @version 1.2.0
	 */
	INSTANCE;

	/**
	 * @description 入库组件的类名比架构元素类名多的尾名
	 * 
	 * @author quark
	 * @date 2020年2月27日 下午4:55:36
	 * @version 1.2.0
	 */
	private final String STORAGE = "Storage";

	/**
	 * @description 生成入库组件【字节码生成】
	 * @param <T>      根据泛型确定返回类型
	 * @param zclass   需要生成入库组件对应的架构元素的类
	 * @param isFirest 入库组件的类
	 * @return 字节码生成类的异常
	 * @throws Exception 生成组件异常
	 *
	 * @date 2020年2月27日 下午4:57:22
	 * @version 1.2.0
	 */
	public synchronized <T> Class<?> buildStorage(Class<T> zclass) throws Exception {
		if (Modifier.isAbstract(zclass.getModifiers())) {
			throw new RuntimeException("抽象forest架构元素无法生成入库组件");
		}
		// 判断入库组件是否已经存在【存在就直接返回】
		String classSimpleName = zclass.getSimpleName();
		try {
			return Class.forName(zclass.getName() + STORAGE);
		} catch (ClassNotFoundException e) {
			LOGGER.info("字节码创建{}的架构元素入库组建", classSimpleName);
		}
		// 获得入库组件的类名
		String className = classSimpleName + STORAGE;
		String absoluteClassName = zclass.getName() + STORAGE;
		// 创建入库组件的类
		ClassPool classPool = ClassPool.getDefault();
		// 加入类加载器
		classPool.insertClassPath(new ClassClassPath(this.getClass()));
		CtClass ctClass = classPool.makeClass(absoluteClassName, classPool.get(ForestRebarStorage.class.getName()));
		// 添加静态单例属性
		CtField enameField = new CtField(classPool.getCtClass(absoluteClassName), capitalizeFirest(className), ctClass);
		enameField.setModifiers(Modifier.PRIVATE + Modifier.STATIC);
		ctClass.addField(enameField);
		// 添加私有的构造方法【懒双重锁单例模式，防止反射攻击优化】
		CtConstructor ctConstructor = new CtConstructor(new CtClass[] {}, ctClass);
		StringBuilder buffer = new StringBuilder();
		StringBuilder append = buffer.append("{\nsynchronized  (").append(absoluteClassName).append(".class) {\n")
				.append("if (singletonFlag == true)\n").append("throw new RuntimeException(\"受到反射攻击\");\n")
				.append("singletonFlag = true;\n").append("LOGGER.info(\"【单例】").append(classSimpleName)
				.append("入库组件初始化\");\n}\n}");
		ctConstructor.setBody(append.toString());
		ctConstructor.setModifiers(Modifier.PRIVATE);
		ctClass.addConstructor(ctConstructor);
		// 添加获取单例的静态方法
		CtMethod methodGetInstance = new CtMethod(classPool.get(absoluteClassName), "yaoZaiJuan", new CtClass[] {},
				ctClass);
		methodGetInstance.setModifiers(Modifier.PUBLIC + Modifier.STATIC + Modifier.FINAL);
		StringBuilder methodBodyGetInstance = new StringBuilder();
		methodBodyGetInstance.append("{\nif (" + capitalizeFirest(className) + " == null) {")
				.append("synchronized (" + absoluteClassName + ".class) {")
				.append("if (" + capitalizeFirest(className) + " == null) {")
				.append(capitalizeFirest(className) + " = new " + absoluteClassName + "();").append("}\n}\n}\n")
				.append("return " + capitalizeFirest(className) + ";\n}");
		methodGetInstance.setBody(methodBodyGetInstance.toString());
		ctClass.addMethod(methodGetInstance);
		// 添加获取架构元素的方法
		CtMethod methodGetForestRebar = new CtMethod(
				classPool.get("org.aerie.forest.core.frame.rebar.entity.AbstractForestRebar"), "getForestRebar",
				new CtClass[] {}, ctClass);
		methodGetForestRebar.setModifiers(Modifier.PROTECTED);
		String methodBodyGetForestRebar = "{\nreturn (org.aerie.forest.core.frame.rebar.entity.AbstractForestRebar)"
				+ zclass.getName() + ".getInstance();\n}";
		methodGetForestRebar.setBody(methodBodyGetForestRebar);
		ctClass.addMethod(methodGetForestRebar);
		return ctClass.toClass(ForestFrameContext.INSTANCE.forestClassLoader, null);
	}

	/**
	 * @description 将字符串首字母小写
	 * @param str 需要处理的字符串
	 * @return 处理后的字符串
	 *
	 * @date 2020年2月27日 下午5:02:19
	 * @version 1.2.0
	 */
	private String capitalizeFirest(String str) {
		return str.substring(0, 1).toLowerCase() + str.substring(1);
	}
}
